package com.faner.fast.util;

import cn.hutool.core.util.IdUtil;
import com.faner.fast.exception.FileTooLargeException;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.security.MessageDigest;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * description: FileUtil
 * date: 2020/11/26 15:19
 * author: faner
 */
@Slf4j
public class FileUtil {

    /**
     * 系统临时目录
     * <br>
     * windows 包含路径分割符，但Linux 不包含,
     * 在windows \\==\ 前提下，
     * 为安全起见 同意拼装 路径分割符，
     * <pre>
     *       java.io.tmpdir
     *       windows : C:\Users/xxx\AppData\Local\Temp\
     *       linux: /temp
     * </pre>
     */
    public static final String SYS_TEM_DIR = System.getProperty("java.io.tmpdir") + File.separator;
    /**
     * 定义GB的计算常量
     */
    private static final int GB = 1024 * 1024 * 1024;
    /**
     * 定义MB的计算常量
     */
    private static final int MB = 1024 * 1024;
    /**
     * 定义KB的计算常量
     */
    private static final int KB = 1024;

    /**
     * 格式化小数
     */
    private static final DecimalFormat DF = new DecimalFormat("0.00");

    public static final String IMAGE = "图片";
    public static final String TXT = "文档";
    public static final String MUSIC = "音乐";
    public static final String VIDEO = "视频";
    public static final String OTHER = "其他";

    private static List<String> filePathList = new ArrayList<String>();


    /**
     * MultipartFile转File
     */
    public static File toFile(MultipartFile multipartFile) {
        // 获取文件名
        String fileName = multipartFile.getOriginalFilename();
        // 获取文件后缀
        String prefix = "." + getExtensionName(fileName);
        File file = null;
        try {
            // 用uuid作为文件名，防止生成的临时文件重复
            file = File.createTempFile(IdUtil.simpleUUID(), prefix);
            // MultipartFile to File
            multipartFile.transferTo(file);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }

        return file;
    }



    /**
     * file转MultipartFile
     */
    @SneakyThrows
    public static MultipartFile toMultipartFile(File file) {
        FileInputStream input = new FileInputStream(file);
        MultipartFile multipartFile = new MockMultipartFile("file", file.getName(), "text/plain", org.apache.commons.compress.utils.IOUtils.toByteArray(input));
        return multipartFile;
    }

    /**
     * inputStream 转 File
     */
    static File inputStreamToFile(InputStream ins, String name) throws Exception {
        File file = new File(SYS_TEM_DIR + name);
        if (file.exists()) {
            return file;
        }
        OutputStream os = new FileOutputStream(file);
        int bytesRead;
        int len = 8192;
        byte[] buffer = new byte[len];
        while ((bytesRead = ins.read(buffer, 0, len)) != -1) {
            os.write(buffer, 0, bytesRead);
        }
        os.close();
        ins.close();
        return file;
    }
    /**
     * 获取文件扩展名，不带 .
     */
    public static String getExtensionName(String filename) {
        int index = filename.lastIndexOf('.');
        return filename.substring(index+1);
    }

    /**
     * Java文件操作 获取不带扩展名的文件名
     */
    public static String getFileNameNoEx(String filename) {
        int index = filename.lastIndexOf('.');
        return filename.substring(0, index);
    }

    /**
     * 文件大小转换
     */
    public static String getSize(long size) {
        String resultSize;
        if (size / GB >= 1) {
            //如果当前Byte的值大于等于1GB
            resultSize = DF.format(size / (float) GB) + "GB   ";
        } else if (size / MB >= 1) {
            //如果当前Byte的值大于等于1MB
            resultSize = DF.format(size / (float) MB) + "MB   ";
        } else if (size / KB >= 1) {
            //如果当前Byte的值大于等于1KB
            resultSize = DF.format(size / (float) KB) + "KB   ";
        } else {
            resultSize = size + "B   ";
        }
        return resultSize;
    }



    /**
     * 将文件名解析成文件的上传路径
     */
    public static File upload(MultipartFile file, String filePath) {
        Date date = new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhhmmssS");
        String name = getFileNameNoEx(file.getOriginalFilename());
        String suffix = getExtensionName(file.getOriginalFilename());
        String nowStr = "-" + format.format(date);
        try {
            String fileName = name + nowStr + "." + suffix;
            String path = filePath + fileName;
            // getCanonicalFile 可解析正确各种路径
            File dest = new File(path).getCanonicalFile();
            // 检测是否存在目录
            if (!dest.getParentFile().exists()) {
                if (!dest.getParentFile().mkdirs()) {
                    System.out.println("was not successful.");
                }
            }
            // 文件写入
            file.transferTo(dest);
            return dest;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    public static String getFileType(String type) {
        String documents = "txt doc pdf ppt pps xlsx xls docx";
        String music = "mp3 wav wma mpa ram ra aac aif m4a";
        String video = "avi mpg mpe mpeg asf wmv mov qt rm mp4 flv m4v webm ogv ogg";
        String image = "bmp dib pcp dif wmf gif jpg tif eps psd cdr iff tga pcd mpt png jpeg";
        if (image.contains(type)) {
            return IMAGE;
        } else if (documents.contains(type)) {
            return TXT;
        } else if (music.contains(type)) {
            return MUSIC;
        } else if (video.contains(type)) {
            return VIDEO;
        } else {
            return OTHER;
        }
    }

    public static void checkSize(long maxSize, long size) {
        // 1M
        int len = 1024 * 1024;
        if (size > (maxSize * len)) {
            throw new FileTooLargeException("文件超出规定大小");
        }
    }

    /**
     * 判断两个文件是否相同
     */
    public static boolean check(File file1, File file2) {
        String img1Md5 = getMd5(file1);
        String img2Md5 = getMd5(file2);
        return img1Md5.equals(img2Md5);
    }

    /**
     * 判断两个文件是否相同
     */
    public static boolean check(String file1Md5, String file2Md5) {
        return file1Md5.equals(file2Md5);
    }

    /**
     * 将文件转换成byte数组
     * @param file
     * @return byte[]
     */
    public static byte[] getByte(File file) {
        // 得到文件长度
        byte[] b = new byte[(int) file.length()];
        try {
            InputStream in = new FileInputStream(file);
            try {
                System.out.println(in.read(b));
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }finally {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } catch (FileNotFoundException e) {
            log.error(e.getMessage(), e);
            return null;
        }
        return b;
    }

    /**
     * 获取文件md5值
     */
    public static String getMd5(File file) {
        return getMd5(getByte(file));
    }

    public static String getMd5(byte[] bytes) {
        return DigestUtils.md5DigestAsHex(bytes);
    }

    /**
     * 判断文件是否存在
     * @param filePath
     * @return
     */
    public static boolean exists(String filePath) {
        boolean exists = false;
        File file = new File(filePath);
        if (file.exists()) {
            exists = true;
        }
        return exists;
    }
    /**
     * 删除指定文件夹
     *
     * @param filePath
     */
    public static void deleteDirectory(String filePath) {
        FileUtils.deleteQuietly(new File(filePath));
    }

    /**
     * 删除指定文件
     * @param filePath
     */
    public static void deleteFile(String filePath) {
        try {
            FileUtils.forceDelete(new File(filePath));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 查找指定路径下指定后缀的所有文件(非递归查找）
     *
     * @param filePath      文件目录
     * @param extensionName 文件扩展名
     */
    public static List<String> getFileUnderFolder(String filePath, String extensionName) {
        List<String> filPathList = new ArrayList<String>();
        File file = new File(filePath);
        File[] fileList = file.listFiles();
        for (File f : fileList) {
            if (f.isFile() && f.getName().endsWith(extensionName)) {
                filPathList.add(f.getAbsolutePath());
            }
        }
        return filPathList;
    }

    /**
     * 查找指定路径下指定后缀的所有文件(递归查找）
     *
     * @param filePath      文件目录
     * @param extensionName 文件扩展名
     */
    public static List<String> getFileUnderFolderCursively(String filePath, String extensionName) {
        File file = new File(filePath);
        File[] fileList = file.listFiles();
        for (File f : fileList) {
            if (f.isFile() && f.getName().endsWith(extensionName)) {
                filePathList.add(f.getAbsolutePath());
            } else if (f.isDirectory()) {
                getFileUnderFolderCursively(f.getAbsolutePath(), extensionName);
            }
        }
        return filePathList;
    }

    /**
     * 递归复制指定路径下指定后缀的所有文件到指定目录
     *
     * @param filePath
     * @param extensionName
     */
    public static void copyFilesUnderFolderCursively(String filePath, String extensionName, String dstPath) {
        File file = new File(filePath);
        File[] fileList = file.listFiles();
        for (File f : fileList) {
            if (f.isFile() && f.getName().endsWith(extensionName)) {
                try {
                    FileUtils.copyFileToDirectory(f, new File(dstPath));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else if (f.isDirectory()) {
                copyFilesUnderFolderCursively(f.getAbsolutePath(), extensionName, dstPath);
            }
        }
    }

    /**
     * 读取文件内容
     * @param filePath
     * @param charsetName 编码格式
     * @return
     */
    public static String readFileContent(String filePath, String charsetName) {
        String content = "";
        File file = new File(filePath);
        if (file.exists()) {
            Long fileLength = file.length();
            byte[] fileContent = new byte[fileLength.intValue()];
            try {
                FileInputStream in = new FileInputStream(file);
                in.read(fileContent);
                in.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                content = new String(fileContent, charsetName);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        return content;
    }

    /**
     * 读取文件内容
     */
    public static ArrayList<String> readFileContentByLine(String filePath, String charsetName) {
        ArrayList<String> list = new ArrayList<String>();
        String str = "";
        FileInputStream fis = null;
        InputStreamReader isr = null;
        BufferedReader br = null; // 用于包装InputStreamReader,提高处理性能，因为BufferedReader有缓冲，InputStreamReader则没有

        try {
            fis = new FileInputStream(filePath); // FileInputStream
            // 从文件系统中的某个文件中获取字节
            isr = new InputStreamReader(fis, charsetName);// InputStreamReader是字节流通往字符流的桥梁
            br = new BufferedReader(isr);// 从字符输入流中读取文件中的内容，封装了一个new
            while ((str = br.readLine()) != null) {
                list.add(str);
            }
        } catch (FileNotFoundException e) {
            System.out.println("找不到指定文件");
        } catch (IOException e) {
            System.out.println("读取文件失败");
        } finally {
            try {
                br.close();
                isr.close();
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return list;
    }


    /**
     * 下载文件
     *
     * @param request  /
     * @param response /
     * @param file     /
     */
    public static void downloadFile(HttpServletRequest request, HttpServletResponse response, File file, boolean deleteOnExit) {
        response.setCharacterEncoding(request.getCharacterEncoding());
        response.setContentType("application/octet-stream");
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(file);
            response.setHeader("Content-Disposition", "attachment; filename=" + file.getName());
            IOUtils.copy(fis, response.getOutputStream());
            response.flushBuffer();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                    if (deleteOnExit) {
                        file.deleteOnExit();
                    }
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
        }
    }




}
